<?php
	
	/**
	  *	This file is responsible for defining a class
	  *
	  *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
	  *	@version 0.0
	  */
	
	if ( !defined( 'SECURITY' ) ) {
		die( 'Direct access to this script is not allowed!' );
	}
	
	/**
	  *	This class is responsible for documenting packets
	  *
	  *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
	  *	@version 0.0
	  */
	class Documentator {
		
		/**
		 *	This parameter stores todo file lines
		 *
		 *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		 *	@var array
		 */
		private $todo_lines;
		
		/**
		 *	This parameter stores current packet name
		 *
		 *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		 *	@var string
		 */
		private $packet_name;
		
		/**
		 *	This parameter stores packet version
		 *
		 *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		 *	@var string
		 */
		private $version;
		
		/**
		 *	This parameter stores current file address
		 *
		 *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		 *	@var string
		 */
		private $file_address;
		
		/**
		 *	This parameter stores file cache name
		 *
		 *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		 *	@var string
		 */
		private $file_cache;
		
		/**
		 *	This parameter stores file cache for interpretation
		 *
		 *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		 *	@var array
		 */
		private $file_lines;
		
		/**
		 *	This parameter stores last scanned class name
		 *
		 *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		 *	@var string
		 */
		private $last_class_name;
		
		/**
		 *	This parameter stores  last analysed comment cache line
		 *
		 *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		 *	@var int
		 */
		private $last_comment_cache_line;
		
		/**
		 *	This parameter stores single comment cache for interpretation
		 *
		 *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		 *	@var string
		 */
		private $comment_cache;
		
		/**
		  *	This method is a class constructor
		  *
		  *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		  *	@version 0.0
		  */
		public function __construct() {
			
			$this->last_comment_cache_line = 0;
			
		}
		
		/**
		  *	This method performs documentation iteration
		  *
		  *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		  *	@version 0.0
		  *
		  *	@p string packet_name - name of the currently opened packet
		  *	@p string version - version of the packet
		  *
		  *	@return bool true if finished
		  */
		public function performIteration( $packet_name, $version ) {
			
			// Save argument values
			$this->packet_name = $packet_name;
			$this->version = $version;
			
			// Make sure packet cache exists
			
			if ( !file_exists( constant( 'DATA_ADDRESS' ) . '/' . $packet_name . '/' . $version ) ) {
				
				SimpleDirectory::createDirectories( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $packet_name . '/' . $version . '/classes' ) );
				SimpleDirectory::createDirectories( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $packet_name . '/' . $version . '/files' ) );
				
				if ( !file_exists( constant( 'DATA_ADDRESS' ) . '/' . $packet_name . '/desc' ) ) {
					SimpleFile::create( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $packet_name . '/desc' ) );
				}
				
				$file_list = array(
					'iteration',
					'files_cache',
					'info',
					'todos',
					'todos_temp',
				);
				
				foreach( $file_list as $file ) {
					SimpleFile::create( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $packet_name . '/' . $version . '/' . $file ) );
				}
				
				if ( !file_exists( constant( 'DATA_ADDRESS' ) . '/' . $packet_name . '/' . $version . '/desc' ) ) {
					SimpleFile::create( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $packet_name . '/' . $version . '/desc' ) );
				}
				
			}
			
			// Get todo lines
			
			$this->todo_lines = SimpleFile::getLines( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/todos_temp', 'external_address' => true ) );
			
			if ( empty( $this->todo_lines ) ) {
				$this->todo_lines = array();
			}	
			
			// Get iteration
			
			$iteration = $this->getIteration();
			
			// Select action
			
			if ( !$iteration ) {
				if ( !$this->loadFileTree() ) {
					return false;
				}
			} elseif( $iteration == '[DIFF]' ) {
				if ( !$this->saveDiffInformation() ) {
					$this->resetIteration();
				}
			} else {
				if ( !$this->scanFile( $iteration ) ) {
					$this->resetIteration();
				}
			}
			
			// Next iteration
			$result = $this->setNextIteration();
			
			return $result;
			
		}
		
		/**
		  *	This method gets current iteration file or action
		  *
		  *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		  *	@version 0.0
		  *
		  *	@return string file or action name
		  */
		private function getIteration() {
			
			$iteration_address = constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/iteration';
			
			$lines = SimpleFile::getLines( array( 'address' => $iteration_address, 'include_empy' => true, 'external_address' => true ) );
			
			if ( $lines ) {
				return $lines[1];
			} else {
				return '';
			}
			
		}
		
		/**
		  *	This method increments iteration
		  *
		  *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		  *	@version 0.0
		  *
		  *	@return bool true if finished
		  */
		private function setNextIteration() {
			
			$iteration_address = constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/iteration';
			$file_list_address = constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/files_cache';
			
			$current_iteration = $this->getIteration();
			
			if ( !$current_iteration ) {
				
				$files = SimpleFile::getLines( array( 'address' => $file_list_address, 'include_empy' => true, 'external_address' => true ) );
				
				if ( !empty( $files ) ) {
					$first_file = $files[1];
					list( $file_address, $file_cache ) = explode( '|', $first_file );
					$lines = array( $file_cache );
					SimpleFile::clear( array( 'address' => $iteration_address ) );
					SimpleFile::appendFile(array( 'address' => $iteration_address, 'lines' => $lines ) );
				} else {
					$lines = array( '[DIFF]' );
					SimpleFile::clear( array( 'address' => $iteration_address ) );
					SimpleFile::appendFile( array( 'address' => $iteration_address, 'lines' => $lines ) );
				}
				
			} elseif ( $current_iteration == '[DIFF]' ) {
				
				SimpleFile::clear( array( 'address' => $iteration_address ) );
				$lines = SimpleFile::getLines( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/todos_temp', 'external_address' => true ) );
				SimpleFile::clear( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/todos_temp' ) );
				SimpleFile::clear( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/todos' ) );
				SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/todos', 'lines' => $lines ) );
				return true;
				
			} else {
				
				$files = SimpleFile::getLines( array( 'address' => $file_list_address, 'include_empy' => true, 'external_address' => true ) );
				
				$next_ok = false;
				
				if ( !empty( $files ) ) {
					
					foreach( $files as $file_line ) {
						
						list( $file_address, $file_cache ) = explode( '|', $file_line );
						
						if ( !$next_ok ) {
							if ( $file_cache == $current_iteration ) {
								$next_ok = true;
							}
						} else {
							$lines = array( $file_cache );
							SimpleFile::clear( array( 'address' => $iteration_address ) );
							SimpleFile::appendFile( array( 'address' => $iteration_address, 'lines' => $lines ) );
							$next_ok = false;
							break;
						}
						
					}
					 
				} else {
					$next_ok = true;
				}
				
				if ( $next_ok ) {
					$lines = array( '[DIFF]' );
					SimpleFile::clear( array( 'address' => $iteration_address ) );
					SimpleFile::appendFile( array( 'address' => $iteration_address, 'lines' => $lines ) );
				}
				
			}
			
			return false;
			
		}
		
		/**
		  *	This method resets iterations
		  *
		  *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		  *	@version 0.0
		  */
		private function resetIteration() {
			$iteration_address = constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/iteration';
			SimpleFile::clear( array( 'address' => $iteration_address ) );
		}
		
		/**
		  *	This method loads packed file tree
		  *
		  *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		  *	@version 0.0
		  *
		  *	@return bool true on success
		  */
		private function loadFileTree() {
			
			// Prepare addresses
			
			$packet_address = null;
			
			if ( !isset( CmsDocumentatorConfig::$packets[$this->packet_name]['address'] ) ) {
				return false;
			}
			
			$packet_address = CmsDocumentatorConfig::$base_address . '/' . CmsDocumentatorConfig::$packets[$this->packet_name]['address'];
			
			$tree_cache_address = constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/files_cache';
			
			// Get file tree
				
			$file_tree = ComplexFile::getFileTree( array( 'address' => $packet_address, 'external_address' => true ) );
			
			if ( $file_tree === false ) {
				return false;
			}
				
			// Save files one by one and give them different file cache names
			
			if ( !SimpleFile::clear( array( 'address' => $tree_cache_address ) ) ) {
				return false;
			}
			
			$file_cache_list = array();
			
			if ( !empty( $file_tree ) ) {
				foreach( $file_tree as $key => $file ) {
					if ( strlen( $file ) > 4 ) {
						if ( substr( $file, -4 ) == '.php' ) {
							
							$base_cache_name = basename( $file );
							
							if ( in_array( $base_cache_name, CmsDocumentatorConfig::$packets[$this->packet_name]['ignore_files'] ) ) {
								continue;
							}
							
							if ( !empty( CmsDocumentatorConfig::$packets[$this->packet_name]['ignore_patterns'] ) ) {
								
								$need_skip = false;
								
								foreach ( CmsDocumentatorConfig::$packets[$this->packet_name]['ignore_patterns'] as $pattern ) {
									
									if ( strpos( $file, $pattern ) !== false ) {
										$need_skip = true;
									}
									
								}
								
								if ( $need_skip ) {
									continue;
								}
								
							}
							
							$base_cache_name = substr( $base_cache_name, 0, strlen( $base_cache_name ) - 4 );
							
							$new_file_cache_name = $base_cache_name;
							
							$last_number = 0;
							
							while ( in_array( $new_file_cache_name, $file_cache_list ) ) {
								$last_number++;
								$new_file_cache_name = $base_cache_name . '_' . $last_number;
							}
							
							$file_cache_list[] = $new_file_cache_name;
							
							$lines = array( $file . '|' . $new_file_cache_name );
							
							if ( !SimpleFile::appendFile( array( 'address' => $tree_cache_address, 'lines' => $lines ) ) ) {
								return false;
							}
							
						}
					}
				}
			}
			
			return true;
			
		}
		
		/**
		  *	This method scans a single file
		  *
		  *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		  *	@version 0.0
		  *
		  *	@p  - string file_cache - file cache name for scanning
		  *
		  *	@return bool true on success
		  */
		private function scanFile( $file_cache ) {
			
			$this->file_cache = $file_cache;
			$this->file_address = $this->getFileAddressByCacheName( $file_cache );
			
			if ( $this->file_address === false ) {
				return false;
			}
			
			// Read all the file
			
			$this->file_lines = SimpleFile::getLines( array( 'address' => $this->file_address, 'include_empty' => true, 'external_address' => true ) );
			
			// Create files
			
			SimpleDirectory::createDirectories( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/files/' . $file_cache . '/defines' ) );
			
			$file_list = array(
				'desc',
				'classes',
			);
			
			foreach( $file_list as $file ) {
				SimpleFile::create( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/files/' . $file_cache . '/' . $file ) );
			}
			
			// Get all special comments one by one and decide what kind of comment that is
			
			while ( $this->loadNextCommentCache() ) {
				
				if ( count( $this->comment_cache ) > 0 ) {
					
					$this->saveTodos();
					
					$last_line = trim( $this->comment_cache[count( $this->comment_cache ) - 1] );
					
					if ( strlen( $last_line ) > 0 ) {
						
						$words = explode( ' ', $last_line );
						
						foreach( $words as $key => $word ) {
							$word = trim( $word );
							if ( empty( $word ) ) {
								unset( $words[$key] );
							}
						}
						
						if ( empty( $words ) ) {
							continue;
						} else {
							ksort( $words );
						}
						
						if ( substr( $words[0], 0, strlen( 'define' ) ) == 'define' ) {
							
							$this->saveDefinition();
							
						} elseif ( in_array( 'class', $words ) || in_array( 'interface', $words ) ) {
							
							$this->saveClass();
							
						} elseif ( in_array( 'function', $words ) ) {
							
							$this->saveMethod();
							
						} else {
							
							$this->saveProperty();
							
						}
						
					} else {
						
						$this->saveFile();
						
					}
					
				}
				
			}
			
			return true;
			
		}
		
		/**
		  *	This method returns full file address by its cache name
		  *
		  *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		  *	@version 0.0
		  *
		  *	@p string file_cache - file cache name
		  *
		  *	@return string/false string file address or false on error
		  */
		private function getFileAddressByCacheName( $file_cache ) {
			
			$tree_cache_address = constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/files_cache';
			
			$file_list = SimpleFile::getLines( array( 'address' => $tree_cache_address, 'external_address' => true ) );
			
			if ( !empty( $file_list ) ) {
				
				foreach( $file_list as $file_info ) {
					
					list( $address, $cache ) = explode( '|', $file_info );
					
					if ( $cache == $file_cache ) {
						return $address;
					}
					
				}
				
			}
			
			return false;
			
		}
		
		/**
		  *	This method replaces brakes into new lines in comment cache parameter
		  *
		  *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		  *	@version 0.0
		  */
		private function replaceBrakesInCommentCache() {
			
			// Check if brakes exist
			$brakes_exist = false;
			
			if ( !empty( $this->comment_cache ) ) {
				foreach( $this->comment_cache as $line ) {
					if ( strpos( $line, '<br />' ) ) {
						$brakes_exist = true;
						break;
					}
				}
			}
			
			// Use <br /> and @ only for new lines
			if ( $brakes_exist ) {
				
				$new_lines = array();
				$index = 0;
				
				foreach( $this->comment_cache as $line_num => $line ) {
					
					if ( $line_num == ( count( $this->comment_cache ) - 1 ) ) {
						
						$new_lines[] = $line;
						
					} else {
					
						if ( substr( trim( $line ), 0, 1 ) == '@' ) {
							$index++;
						}
						
						$line_parts = explode( '<br />', $line );
						
						foreach( $line_parts as $key => $part ) {
							
							if ( isset( $new_lines[$index] ) ) {
								$new_lines[$index] .= $part;
							} else {
								$new_lines[$index] = $part;
							}
							
							if ( $key != ( count( $line_parts ) - 1 ) ) {
								$index++;
							}
							
						}
						
					}
					
				}
				
				$this->comment_cache = $new_lines;
				
			}
			
		}
		
		/**
		  *	This method loads next comment into cache
		  *
		  *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		  *	@version 0.0
		  *
		  *	@return bool true on success and false on error
		  */
		private function loadNextCommentCache() {
			
			$lines = array();
			
			$comment_found = false;
			$last_line_needed = false;
			
			for( $i = $this->last_comment_cache_line + 1; $i <= count( $this->file_lines ); $i++ ) {
				
				if ( !isset( $this->file_lines[$i] ) ) {
					$this->file_lines = 0;
					return false;
				}
				
				$line = $this->file_lines[$i];
				$line = ltrim( $line );
				
				if ( $comment_found ) {
					
					if ( $last_line_needed ) {
						
						$lines[] = $line;
						$this->comment_cache = $lines;
						$this->last_comment_cache_line = $i;
						$this->replaceBrakesInCommentCache();
						return true;
						
					} else {
						
						if ( ( strlen( $line ) >= 2 ) && ( substr( $line, 0, 2 ) == '*/' ) ) {
							
							$last_line_needed = true;
							
						} elseif ( ( strlen( $line ) >= 1 ) && ( substr( $line, 0, 1 ) == '*' ) ) {
							
							if ( strlen( $line ) > 1 ) {
								$line = substr( $line, 1, strlen( $line ) - 1 );
							} else {
								$line = '';
							}
							
							$lines[] = $line;
							
						} else {
							
							$lines = array();
							$comment_found = false;
							
						}
						
					}
					
				} else {
					
					if ( ( strlen( $line ) >= 3 ) && ( substr( $line, 0, strlen( '/**' ) ) == '/**' ) ) {
						
						$comment_found = true;
						
					}
					
				}
				
			}
			
			$this->last_comment_cache_line = 0;
			return false;
			
		}
		
		/**
		  *	This method saves class comment information
		  *
		  *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		  *	@version 0.0
		  *
		  *	@return bool true on success
		  */
		private function saveClass() {
			
			// Get class name and some properties
			
			if ( empty( $this->comment_cache ) ) {
				return false;
			}
			
			$last_line = $this->comment_cache[count( $this->comment_cache ) - 1];
			
			$property_line = '';
			
			$words = explode( ' ', $last_line );
			
			if ( in_array( 'static', $words ) ) {
				$property_line .= 'static ';
			}
			
			if ( in_array( 'private', $words ) ) {
				$property_line .= 'private ';
			} elseif ( in_array( 'protected', $words ) ) {
				$property_line .= 'protected ';
			}
			
			$this_is_name = false;
			$class_name = '';
			
			foreach( $words as $word ) {
				
				if ( $this_is_name ) {
					
					$class_info = $word;
					$class_array = explode( '(', $class_info );
					$class_info = $class_array[0];
					$class_array = explode( '{', $class_info );
					$class_name = $class_array[0];
					break;
					
				} else {
					
					if ( ( $word =='interface' ) || ( $word == 'class' ) ) {
						$this_is_name = true;
					}
					
				}
				
			}
			
			$this->last_class_name = $class_name;
			
			// Create files
			
			SimpleDirectory::createDirectories( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $class_name . '/methods' ) );
			SimpleDirectory::createDirectories( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $class_name . '/properties' ) );
			
			$file_list = array(
				'desc',
			);
			
			foreach( $file_list as $file ) {
				SimpleFile::create( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $class_name . '/' . $file ) );
			}
			
			// Save version
			
			$version = '0';
			
			foreach( $this->comment_cache as $line ) {
				$line = trim( $line );
				if ( ( strlen( $line ) > strlen( '@version ' ) ) && ( substr( $line, 0, strlen( '@version' ) ) == '@version' ) ) {
					$version = trim( substr( $line, strlen( '@version' ) ) );
					empty( $version ) ? '0' : $version;
					break;
				}
			}
			
			$lines = array( $version );
			SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $class_name . '/desc', 'lines' => $lines ) );
			
			// Save authors
			
			$authors_count = 0;
			$authors_array = array();
			
			foreach( $this->comment_cache as $line ) {
				$line = trim( $line );
				if ( ( strlen( $line ) > strlen( '@author ' ) ) && ( substr( $line, 0, strlen( '@author' ) ) == '@author' ) ) {
					$author = trim( substr( $line, strlen( '@author' ) ) );
					if ( !empty( $author ) ) {
						$authors_array[] = $author;
						$authors_count++;
					}
				}
			}
			
			$lines = array();
			
			$lines[] = (string)$authors_count;
			
			if ( !empty( $authors_array ) ) {
				foreach( $authors_array as $author ) {
					$lines[] = $author;
				}
			}
			
			SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $class_name . '/desc', 'lines' => $lines ) );
			
			// Save description and additional parameters
			
			$lines = array( $property_line );
			SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $class_name . '/desc', 'lines' => $lines ) );
			
			$description_lines = array();
			
			foreach( $this->comment_cache as $key => $line ) {
				if ( ( strlen( trim( $line ) ) > 0 ) && ( substr( trim( $line ), 0, 1 ) == '@' ) ) {
					break;
				} else {
					if ( $key != count( $this->comment_cache ) - 1 ) {
						$description_lines[] = $line;
					}
				}
			}
			
			$lines = $description_lines;
			
			SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $class_name . '/desc', 'lines' => $lines ) );
			
			// Register class
			
			$lines = array( $class_name );
			SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/files/' . $this->file_cache . '/classes', 'lines' => $lines ) );
			
			return true;
			
		}
		
		/**
		  *	This method saves property comment information
		  *
		  *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		  *	@version 0.0
		  *
		  *	@return bool true on success
		  */
		private function saveProperty() {
			
			// Save property name  and get additional properties
			
			if ( empty( $this->comment_cache ) ) {
				return false;
			}
			
			$last_line = $this->comment_cache[count( $this->comment_cache ) - 1];
			
			$property_line = '';
			
			$words = explode( ' ', $last_line );
			
			if ( in_array( 'static', $words ) ) {
				$property_line .= 'static ';
			}
			
			if ( in_array( 'private', $words ) ) {
				$property_line .= 'private ';
			} elseif( in_array( 'protected', $words ) ) {
				$property_line .= 'protected ';
			}
			
			$property_name = '';
			
			foreach( $words as $word ) {
				if ( substr( $word, 0, 1 ) == '$' ) {
					$word = substr( $word, 1 );
					$word_array = explode( ';', $word );
					$property_name = $word_array[0];
				}
			}
			
			SimpleFile::create( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $this->last_class_name . '/properties/' . $property_name ) );
			
			// Save version
			
			$version = '0';
			
			foreach( $this->comment_cache as $line ) {
				$line = trim( $line );
				if ( ( strlen( $line ) > strlen( '@version ' ) ) && ( substr( $line, 0, strlen( '@version' ) ) == '@version' ) ) {
					$version = trim( substr( $line, strlen( '@version' ) ) );
					empty( $version ) ? '0' : $version;
					break;
				}
			}
			
			$lines = array( $version );
			SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $this->last_class_name . '/properties/' . $property_name, 'lines' => $lines ) );
			
			// Save authors
			
			$authors_count = 0;
			$authors_array = array();
			
			foreach( $this->comment_cache as $line ) {
				$line = trim( $line );
				if ( ( strlen( $line ) > strlen( '@author ' ) ) && ( substr( $line, 0, strlen( '@author' ) ) == '@author' ) ) {
					$author = trim( substr( $line, strlen( '@author' ) ) );
					if ( !empty( $author ) ) {
						$authors_array[] = $author;
						$authors_count++;
					}
				}
			}
			
			$lines = array();
			
			$lines[] = (string)$authors_count;
			
			if ( !empty( $authors_array ) ) {
				foreach( $authors_array as $author ) {
					$lines[] = $author;
				}
			}
			
			SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $this->last_class_name . '/properties/' . $property_name, 'lines' => $lines ) );
			
			// Save additional properties
			
			$lines = array( $property_line );
			SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $this->last_class_name . '/properties/' . $property_name, 'lines' => $lines ) );
			
			// Save property data type
			
			$type = 'mixed';
			
			foreach( $this->comment_cache as $line ) {
				$line = trim( $line );
				if ( ( strlen( $line ) > strlen( '@var ' ) ) && ( substr( $line, 0, strlen( '@var' ) ) == '@var' ) ) {
					$type = trim( substr( $line, strlen( '@var' ) ) );
					empty( $type ) ? 'mixed' : $type;
					break;
				}
			}
			
			$lines = array( $type );
			SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $this->last_class_name . '/properties/' . $property_name, 'lines' => $lines ) );
			
			// Save description
			
			$description_lines = array();
			
			foreach( $this->comment_cache as $key => $line ) {
				if ( ( strlen( trim( $line ) ) > 0 ) && ( substr( trim( $line ), 0, 1 ) == '@' ) ) {
					break;
				} else {
					if ( $key != count( $this->comment_cache ) - 1 ) {
						$description_lines[] = $line;
					}
				}
			}
			
			$lines = $description_lines;
			SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $this->last_class_name . '/properties/' . $property_name, 'lines' => $lines ) );
			
			return true;
			
		}
		
		/**
		  *	This method saves method comment information
		  *
		  *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		  *	@version 0.0
		  *
		  *	@return bool true on success
		  */
		private function saveMethod() {
			
			// Save method name and additional properties
			
			if ( empty( $this->comment_cache ) ) {
				return false;
			}
			
			$last_line = $this->comment_cache[count( $this->comment_cache ) - 1];
			
			$property_line = '';
			
			$words = explode( ' ', $last_line );
			
			if ( in_array( 'static', $words ) ) {
				$property_line .= 'static ';
			}
			
			if ( in_array( 'private', $words ) ) {
				$property_line .= 'private ';
			} elseif( in_array( 'protected', $words ) ) {
				$property_line .= 'protected ';
			}
			
			$method_name = '';
			
			$name_now = false;
			
			foreach( $words as $word ) {
				
				if ( $name_now ) {
					
					$method_name = $word;
					$name_array = explode( '(', $method_name );
					$method_name = $name_array[0];
					break;
					
				} else {
					
					if ( $word == 'function' ) {
						$name_now = true;
					}
					
				}
				
			}
			
			if ( empty( $method_name ) ) {
				return false;
			}
			
			SimpleFile::create( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $this->last_class_name . '/methods/' . $method_name ) );
			
			// Save version
			
			$version = '0';
			
			foreach( $this->comment_cache as $line ) {
				$line = trim( $line );
				if ( ( strlen( $line ) > strlen( '@version ' ) ) && ( substr( $line, 0, strlen( '@version' ) ) == '@version' ) ) {
					$version = trim( substr( $line, strlen( '@version' ) ) );
					empty( $version ) ? '0' : $version;
					break;
				}
			}
			
			$lines = array( $version );
			SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $this->last_class_name . '/methods/' . $method_name, 'lines' => $lines ) );
			
			// Save authors
			
			$authors_count = 0;
			$authors_array = array();
			
			foreach( $this->comment_cache as $line ) {
				$line = trim( $line );
				if ( ( strlen( $line ) > strlen( '@author ' ) ) && ( substr( $line, 0, strlen( '@author' ) ) == '@author' ) ) {
					$author = trim( substr( $line, strlen( '@author' ) ) );
					if ( !empty( $author ) ) {
						$authors_array[] = $author;
						$authors_count++;
					}
				}
			}
			
			$lines = array();
			
			$lines[] = (string)$authors_count;
			
			if ( !empty( $authors_array ) ) {
				foreach( $authors_array as $author ) {
					$lines[] = $author;
				}
			}
			
			SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $this->last_class_name . '/methods/' . $method_name, 'lines' => $lines ) );
			
			// Save parameters
			
			$parameter_count = 0;
			$parameter_array = array();
			
			foreach( $this->comment_cache as $key => $line ) {
				
				if ( $key < ( count( $this->comment_cache ) - 1 ) ) {
					
					if ( ( strlen( trim( $line ) ) > strlen( '@param ' ) ) && ( substr( trim( $line ), 0, strlen( '@param' ) ) == '@param' ) ) {
						
						$line = trim( $line );
						
						$first_line = 'old ';
						$parameter_count++;
						$parameter_array[$parameter_count - 1][0] = 2;	// Line count
						
						$words = explode( ' ', $line );
						
						if ( count( $words ) < 3 ) {
							return false;
						}
						
						$first_line .= $words[1];
						
						$parameter_array[$parameter_count - 1][1] = $first_line;
						
						unset( $words[0] );
						
						$rest_of_the_line = implode( ' ', $words );
						
						$parameter_array[$parameter_count - 1][2] = $rest_of_the_line;
						
					} elseif ( ( strlen( trim( $line ) ) > strlen( '@ap ' ) ) && ( substr( trim( $line ), 0, strlen( '@ap' ) ) == '@ap' ) ) {
						
						$line = trim( $line );
						
						$first_line = 'arguments ';
						$parameter_count++;
						$parameter_array[$parameter_count - 1][0] = 2;	// Line count
						
						$words = explode( ' ', $line );
						
						if ( count( $words ) < 3 ) {
							return false;
						}
						
						$first_line .= $words[1];
						
						$parameter_array[$parameter_count - 1][1] = $first_line;
						
						unset( $words[0] );
						
						$rest_of_the_line = implode( ' ', $words );
						
						$parameter_array[$parameter_count - 1][2] = $rest_of_the_line;
						
					} elseif ( ( strlen( trim( $line ) ) > strlen( '@p ' ) ) && ( substr( trim( $line ), 0, strlen( '@p' ) ) == '@p' ) ) {
						
						$line = trim( $line );
						
						$first_line = 'short ';
						$parameter_count++;
						$parameter_array[$parameter_count - 1][0] = 2;	// Line count
						
						$words = explode( ' ', $line );
						
						if ( count( $words ) < 3 ) {
							return false;
						}
						
						$first_line .= $words[1];
						
						$parameter_array[$parameter_count - 1][1] = $first_line;
						
						unset( $words[0] );
						
						$rest_of_the_line = implode( ' ', $words );
						
						$parameter_array[$parameter_count - 1][2] = $rest_of_the_line;
						
					} elseif ( ( strlen( trim( $line ) ) > 1 ) && ( substr( trim( $line ), 0, 1 ) == '@' ) ) {
						
						if ( $parameter_count > 0 ) {
							break;
						}
						
					} else {
						
						if ( $parameter_count > 0 ) {
							$parameter_array[$parameter_count - 1][] = $line;
							$parameter_array[$parameter_count - 1][0]++;
						}
						
					}
					
				}
				
			}
			
			$lines = array( (string)$parameter_count );
			
			if ( !empty( $parameter_array ) ) {
				foreach( $parameter_array as $parameter ) {
					foreach( $parameter as $parameter_line ) {
						$lines[] = $parameter_line;
					}
				}
			}
			
			SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $this->last_class_name . '/methods/' . $method_name, 'lines' => $lines ) );
			
			// Save return value
			
			$lines = array( 0 );
			$return_found = false;
			
			foreach( $this->comment_cache as $key => $line ) {
				
				if ( $key < ( count( $this->comment_cache ) - 1 ) ) {
				
					if ( $return_found ) {
						
						if ( ( strlen( trim( $line ) ) > 1 ) && ( substr( trim( $line ), 0, 1 ) == '@' ) ) {
							break;
						} else {
							$lines[] = $line;
							$lines[0]++;
						}
						
					} else {
						
						if ( ( strlen( trim( $line ) ) > strlen( '@return ' ) ) && ( substr( trim( $line ), 0, strlen( '@return' ) ) == '@return' ) ) {
							
							$line = trim( $line );
							
							$words = explode( ' ', $line );
							
							if ( count( $words ) < 3 ) {
								break;
							}
							
							$lines[0] = 2;
							
							$lines[1] = $words[1];
							
							unset( $words[0] );
							
							$lines[2] = implode( ' ', $words );
							
							$return_found = true;
							
						}
						
					}
					
				}
				
			}
			
			SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $this->last_class_name . '/methods/' . $method_name, 'lines' => $lines ) );
			
			// Save additional properties
			
			$lines = array( $property_line );
			SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $this->last_class_name . '/methods/' . $method_name, 'lines' => $lines ) );
			
			// Save description
			
			$description_lines = array();
			
			foreach( $this->comment_cache as $key => $line ) {
				if ( ( strlen( trim( $line ) ) > 0 ) && ( substr( trim( $line ), 0, 1 ) == '@' ) ) {
					break;
				} else {
					if ( $key != count( $this->comment_cache ) - 1 ) {
						$description_lines[] = $line;
					}
				}
			}
			
			$lines = $description_lines;
			SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $this->last_class_name . '/methods/' . $method_name, 'lines' => $lines ) );
			
			return true;
			
		}
		
		/**
		  *	This method saves file comment information
		  *
		  *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		  *	@version 0.0
		  *
		  *	@return bool true on success
		  */
		private  function saveFile() {
			
			// Save file name
			
			if ( empty( $this->comment_cache ) ) {
				return false;
			}
			
			SimpleDirectory::createDirectories( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/files/' . $this->file_cache . '/defines' ) );
			
			$file_list = array(
				'desc',
				'classes',
			);
			
			foreach( $file_list as $file ) {
				SimpleFile::create( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/files/' . $this->file_cache . '/' . $file ) );
			}
			
			// Save version
			
			$version = '0';
			
			foreach( $this->comment_cache as $line ) {
				$line = trim( $line );
				if ( ( strlen( $line ) > strlen( '@version ' ) ) && ( substr( $line, 0, strlen( '@version' ) ) == '@version' ) ) {
					$version = trim( substr( $line, strlen( '@version' ) ) );
					empty( $version ) ? '0' : $version;
					break;
				}
			}
			
			$lines = array( $version );
			SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/files/' . $this->file_cache . '/desc', 'lines' => $lines ) );
			
			// Save authors
			
			$authors_count = 0;
			$authors_array = array();
			
			foreach( $this->comment_cache as $line ) {
				$line = trim( $line );
				if ( ( strlen( $line ) > strlen( '@author ' ) ) && ( substr( $line, 0, strlen( '@author' ) ) == '@author' ) ) {
					$author = trim( substr( $line, strlen( '@author' ) ) );
					if ( !empty( $author ) ) {
						$authors_array[] = $author;
						$authors_count++;
					}
				}
			}
			
			$lines = array();
			
			$lines[] = (string)$authors_count;
			
			if ( !empty( $authors_array ) ) {
				foreach( $authors_array as $author ) {
					$lines[] = $author;
				}
			}
			
			SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/files/' . $this->file_cache . '/desc', 'lines' => $lines ) );
			
			// Save description
			
			$description_lines = array();
			
			foreach( $this->comment_cache as $key => $line ) {
				if ( ( strlen( trim( $line ) ) > 0 ) && ( substr( trim( $line ), 0, 1 ) == '@' ) ) {
					break;
				} else {
					if ( $key != count( $this->comment_cache ) - 1 ) {
						$description_lines[] = $line;
					}
				}
			}
			
			$lines = $description_lines;
			SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/files/' . $this->file_cache . '/desc', 'lines' => $lines ) );
			
			return true;
			
		}
		
		/**
		  *	This method saves definition comment information
		  *
		  *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		  *	@version 0.0
		  *
		  *	@return bool true on success
		  */
		private function saveDefinition() {
			
			// Save definition name
			
			if ( empty( $this->comment_cache ) ) {
				return false;
			}
			
			$definition_name = null;
			
			foreach( $this->comment_cache as $line ) {
				$line = trim( $line );
				if ( ( strlen( $line ) > strlen( '@name ' ) ) && ( substr( $line, 0, strlen( '@name' ) ) == '@name' ) ) {
					$definition_array = explode( ' ', $line );
					$definition_name = $definition_array[1];
				}
			}
			
			SimpleFile::create( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/files/' . $this->file_cache . '/defines/' . $definition_name ) );
			
			// Save description
			
			$description_lines = array();
			
			foreach( $this->comment_cache as $key => $line ) {
				if ( ( strlen( trim( $line ) ) > 0 ) && ( substr( trim( $line ), 0, 1 ) == '@' ) ) {
					break;
				} else {
					if ( $key != count( $this->comment_cache ) - 1 ) {
						$description_lines[] = $line;
					}
				}
			}
			
			$lines = $description_lines;
			SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/files/' . $this->file_cache . '/defines/' . $definition_name, 'lines' => $lines ) );
			
			return true;
			
		}
		
		/**
		  *	This method saves todo information
		  *
		  *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		  *	@version 0.0
		  */
		private function saveTodos() {
			
			if ( !empty( $this->comment_cache ) ) {
				
				foreach( $this->comment_cache as $line ) {
					
					$line = trim( $line );
					
					if ( substr( $line, 0, 5 ) == '@todo' ) {
						
						if ( strlen( $line ) > 6 ) {
							$line = substr( $line, 6 );
						}
						
						$line = $this->file_address . '|' . $line;
						
						if ( in_array( $line, $this->todo_lines ) ) {
							continue;
						} else {
							$this->todo_lines[] = $line;
							$new_lines = array( $line );
							SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/todos_temp', 'lines' => $new_lines ) );
						}
						
					}
					
				}
				
			}
			
		}
		
		/**
		  *	This method saves information for searching for differencies between versions
		  *
		  *	@author Vytenis Urbonavicius <vytenis.urbonavicius@myhost.lt>
		  *	@version 0.0
		  *
		  *	@return bool true on success
		  */
		private function saveDiffInformation() {
			
			// File address | object type | object name | parent | version
			$information_array = array();
			
			SimpleFile::clear( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/info' ) );
			
			// Get files
				
			$file_array = SimpleFile::getLines( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/files_cache', 'external_address' => true ) );
			
			if ( !empty( $file_array ) ) {
				foreach( $file_array as $key => $file_info ) {
					list( $file_address, $file_cache ) = explode( '|', $file_info );
					$file_array[$key] = array(
						'file_address' => $file_address,
						'file_cache' => $file_cache,
					);
				}
			}
			
			if ( !empty( $file_array ) ) {
				foreach( $file_array as $file_info ) {
					$file_desc = SimpleFile::getLines( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/files/' . $file_info['file_cache'] . '/desc', 'external_address' => true ) );
					if ( empty( $file_desc ) ) {
						$file_desc[1] = '0';
					}
					$lines = array( $file_info['file_address'] . '|file|file|project|' . $file_desc[1] );
					SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/info', 'lines' => $lines ) );
				}
			}
			
			// Get defines
			
			if ( !empty( $file_array ) ) {
				foreach( $file_array as $file_info ) {
					
					$define_files = ComplexFile::getFileTree( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/files/' . $file_info['file_cache'] . '/defines', 'external_address' => true ) );
					
					if ( !empty( $define_files ) ) {
						
						foreach( $define_files as $define_file ) {
							$define_name = basename( $define_file );
							$lines = array( $file_info['file_address'] . '|define|' . $define_name . '|file|0' );
							SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/info', 'lines' => $lines ) );
						}
						
					}
					
				}
			}
			
			// Get classes, methods and properties
			
			if ( !empty( $file_array ) ) {
				foreach( $file_array as $file_info ) {
					
					$class_array = SimpleFile::getLines( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/files/' . $file_info['file_cache'] . '/classes', 'external_address' => true ) );
					
					if ( !empty( $class_array ) ) {
						foreach( $class_array as $class_name ) {
							
							// Save classes
								
								$class_desc = SimpleFile::getLines( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $class_name . '/desc', 'external_address' => true ) );
								if ( empty( $class_desc ) ) {
									$class_desc[1] = '0';
								}
								$lines = array( $file_info['file_address'] . '|class|' . $class_name . '|file|' . $class_desc[1] );
								SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/info', 'lines' => $lines ) );
								
							// Save methods
								
								$method_files = ComplexFile::getFileTree( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $class_name . '/methods', 'external_address' => true ) );
								
								if ( !empty( $method_files ) ) {
									foreach( $method_files as $method_file ) {
										
										$method_name = basename( $method_file );
										$method_desc = SimpleFile::getLines( array( 'address' =>$method_file, 'external_address' => true ) );
										if ( empty( $method_desc ) ) {
											$method_desc[1] = '0';
										}
										$lines = array( $file_info['file_address'] . '|method|' . $method_name . '|' . $class_name . '|' . $method_desc[1] );
										SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/info', 'lines' => $lines ) );
										
									}
								}
								
							// Save properties
								
								$property_files = ComplexFile::getFileTree( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/classes/' . $class_name . '/properties', 'external_address' => true ) );
								
								if ( !empty( $method_files ) ) {
									foreach( $property_files as $property_file ) {
										
										$property_name = basename( $property_file );
										$property_desc = SimpleFile::getLines( array( 'address' =>$property_file, 'external_address' => true ) );
										if ( empty( $property_desc ) ) {
											$property_desc[1] = '0';
										}
										$lines = array( $file_info['file_address'] . '|property|' . $property_name . '|' . $class_name . '|' . $property_desc[1] );
										SimpleFile::appendFile( array( 'address' => constant( 'DATA_ADDRESS' ) . '/' . $this->packet_name . '/' . $this->version . '/info', 'lines' => $lines ) );
										
									}
								}
								
						}
					}
					
				}
			}
			
			return true;
			
		}
		
	}
	
?>